package com.ayf.payment.game.api.channel.youka;

import com.alibaba.fastjson.JSONObject;
import com.ayf.payment.game.api.bean.BaseResData;
import com.ayf.payment.game.api.channel.BaseHandler;
import com.ayf.payment.game.api.channel.youka.res.YouKaAgentPayOrderCreateRes;
import com.ayf.payment.game.api.dto.platform.SubstitutePayConfigDTO;
import com.ayf.payment.game.api.dto.platform.pay.WanXiangPayConfigParamVO;
import com.ayf.payment.game.api.exception.NullSetException;
import com.ayf.payment.game.api.service.platform.SubstitutePayConfigService;
import com.ayf.payment.game.api.type.MerchantPayOrderStatusEnum;
import com.ayf.payment.game.api.utils.KqXmlUtil;
import com.ayf.payment.game.api.utils.MD5Util;
import com.ayf.payment.game.api.utils.SnowFlakeUtils;
import com.swwx.charm.commons.lang.utils.LogPortal;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Component
public class YouKaPayHandler implements BaseHandler {


    public static final String PAY_ORDER_CREATE = "paytransit/paytransfer";

    public static final String PAY_ORDER_QUERY = "paytransit/search";

    @Autowired
    private SubstitutePayConfigService substitutePayConfigService;

    @Override
    public JSONObject orderCreate(JSONObject inputParam) {
        JSONObject resJson = new JSONObject();
        String merchantOrderNo = inputParam.getString("merchant_order_no");
        resJson.put("merchantOrderNo", merchantOrderNo);
        resJson.put("status", MerchantPayOrderStatusEnum.PAY_PROCESSING.getStatus());

        String traceId = inputParam.getString("traceId");

        BigDecimal amount = inputParam.getBigDecimal("amount");
        String username = inputParam.getString("account_name");
        String bankName = inputParam.getString("bank_name");
        String banktype = getBankType(traceId, bankName);
        String bankno = inputParam.getString("account_no");

        Integer substitutePayConfigId = inputParam.getInteger("substitutePayConfigId");
        SubstitutePayConfigDTO substitutePayConfigDTO = substitutePayConfigService.getSubstitutePayConfigById(substitutePayConfigId);
        // 测试使用
//        SubstitutePayConfigDTO substitutePayConfigDTO = getSubstitutePayConfigDTOTest();
        WanXiangPayConfigParamVO wanXiangPayConfigParamVO = substitutePayConfigDTO.getWanXiangPayConfigParamVO();
        String channelPayUrl = wanXiangPayConfigParamVO.getWebsite();
        String returnUrl = wanXiangPayConfigParamVO.getNotifyurl();
        if (StringUtils.isEmpty(channelPayUrl)){
            LogPortal.error("{} 失败，优卡代付下单地址不能为空，订单号:{}",traceId,merchantOrderNo);
            throw new NullSetException(traceId + "下单失败，请稍后重试！");
        }
        if (!channelPayUrl.endsWith("/")){
            channelPayUrl=channelPayUrl.concat("/");
        }
        channelPayUrl=channelPayUrl.concat(PAY_ORDER_CREATE);
        if (StringUtils.isEmpty(returnUrl)){
            LogPortal.error("{} 失败，优卡代付异步通知地址不能为空，订单号:{}",traceId,merchantOrderNo);
            throw new NullSetException(traceId + "下单失败，请稍后重试！");
        }
        if (!returnUrl.endsWith("/")){
            returnUrl=returnUrl.concat("/");
        }
        returnUrl=returnUrl.concat("gameapip/v/yk/pay/agentpay/notify");

        String parter = wanXiangPayConfigParamVO.getParter();
        String key = wanXiangPayConfigParamVO.getKey();

        String payerIp ="";
        String attach = "";
        String bankprovince =inputParam.getString("bank_province");
        String bankcity =inputParam.getString("bank_city");
        String bankbranch =inputParam.getString("bank_branch_bame");
        String banknumber =inputParam.getString("bank_branch_no");
        String sign = getOrderCreateSign(parter,banktype,amount,merchantOrderNo,returnUrl,key);
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("parter",parter);
        paramMap.put("type",banktype);
        paramMap.put("value",String.valueOf(amount));
        paramMap.put("orderid",merchantOrderNo);
        paramMap.put("callbackurl",returnUrl);
        paramMap.put("payerIp",payerIp);
        paramMap.put("attach",attach);
        paramMap.put("sign",sign);
        paramMap.put("bankaccountname",encodeGb2312Str(username));
        paramMap.put("bankaccount",bankno);
        paramMap.put("bankprovince",encodeGb2312Str(bankprovince));
        paramMap.put("bankcity",encodeGb2312Str(bankcity));
        paramMap.put("bankbranch",encodeGb2312Str(bankbranch));
        paramMap.put("banknumber",banknumber);
        paramMap.put("payerIp","");

        BaseResData baseResData =sendGet(traceId,"优卡代付下单",channelPayUrl,paramMap);
        if (baseResData.isProcessing()){
            resJson.put("status", MerchantPayOrderStatusEnum.PAY_PROCESSING.getStatus());
            return resJson;
        }
        if (baseResData.isSuccess()){
            YouKaAgentPayOrderCreateRes youKaAgentPayOrderCreateRes = KqXmlUtil.getObjectFromXML("root",baseResData.getData(), YouKaAgentPayOrderCreateRes.class);
            String code = youKaAgentPayOrderCreateRes.getRet_code();
            String msg = youKaAgentPayOrderCreateRes.getRet_msg();
            if ("1000".equals(code)) { // 业务处理成功
                resJson.put("status", MerchantPayOrderStatusEnum.PAY_PROCESSING.getStatus());
                return resJson;
            } else {
                resJson.put("status", MerchantPayOrderStatusEnum.PAY_FAIL.getStatus());
                resJson.put("failReason", msg);
                return resJson;
            }
        } else {
            resJson.put("status", MerchantPayOrderStatusEnum.PAY_FAIL.getStatus());
            resJson.put("failReason", "支付通道系统繁忙，请稍后重试");
            return resJson;
        }
    }

    @Override
    public JSONObject orderQuery(JSONObject inputParam) {
        JSONObject resJson = new JSONObject();
        String merchantOrderNo = inputParam.getString("merchant_order_no");
        resJson.put("merchantOrderNo", merchantOrderNo);
        resJson.put("status", MerchantPayOrderStatusEnum.PAY_PROCESSING.getStatus());

        String traceId = inputParam.getString("traceId");

        Integer substitutePayConfigId = inputParam.getInteger("substitutePayConfigId");
        SubstitutePayConfigDTO substitutePayConfigDTO = substitutePayConfigService.getSubstitutePayConfigById(substitutePayConfigId);
        // 测试使用
//        SubstitutePayConfigDTO substitutePayConfigDTO = getSubstitutePayConfigDTOTest();

        WanXiangPayConfigParamVO wanXiangPayConfigParamVO = substitutePayConfigDTO.getWanXiangPayConfigParamVO();

        String channelPayUrl = wanXiangPayConfigParamVO.getWebsite();
        if (StringUtils.isEmpty(channelPayUrl)){
            LogPortal.error("{} 失败，优卡代付地址不能为空，订单号:{}",traceId,merchantOrderNo);
            throw new NullSetException(traceId + "优卡代付地址不能为空！");
        }
        if (!channelPayUrl.endsWith("/")){
            channelPayUrl=channelPayUrl.concat("/");
        }
        channelPayUrl=channelPayUrl.concat(PAY_ORDER_QUERY);

        String parter = wanXiangPayConfigParamVO.getParter();
        String key = wanXiangPayConfigParamVO.getKey();

        String sign = getOrderQuerySign(merchantOrderNo, parter, key);
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("orderno",merchantOrderNo);
        paramMap.put("parter",parter);
        paramMap.put("sign",sign);

        BaseResData baseResData =sendGet(traceId,"优卡代付订单查询",channelPayUrl,paramMap);
        if (baseResData.isProcessing()){
            resJson.put("status", MerchantPayOrderStatusEnum.PAY_PROCESSING.getStatus());
            return resJson;
        }
        if (baseResData.isSuccess()){
            JSONObject jsonDate = strToJson(baseResData.getData());
            String opstate = jsonDate.getString("opstate");
            String msg = "";
            Integer status= MerchantPayOrderStatusEnum.PAY_PROCESSING.getStatus();
            if ("0".equals(opstate)){
                status= MerchantPayOrderStatusEnum.PAY_SUCCESS.getStatus();
                msg = "代付成功";
            } else if ("1".equals(opstate)||"2".equals(opstate)||"3".equals(opstate)){
                status= MerchantPayOrderStatusEnum.PAY_PROCESSING.getStatus();
                msg = "处理中";
            }
            resJson.put("status",status);
            resJson.put("failReason",msg);
        } else {
            resJson.put("status", MerchantPayOrderStatusEnum.PAY_PROCESSING.getStatus());
            resJson.put("failReason", "支付通道系统繁忙，请稍后重试");
        }
        return resJson;
    }

    @Override
    public JSONObject balanceQuery(JSONObject inputParam) {
        JSONObject resJson = new JSONObject();
        resJson.put("status", "1");
        resJson.put("balance", "10000000.00");
        return resJson;
    }


    private String getOrderCreateSign(String parter,String banktype,BigDecimal amount,String orderid,String notifyurl,String key) {
        String format = "parter={0}&type={1}&value={2}&orderid={3}&callbackurl={4}{5}";
        String sign = MessageFormat.format(format, parter, banktype,String.valueOf(amount), orderid, notifyurl,key);
        LogPortal.info("{} 优卡代付下单签名原文:{}",orderid,sign);
        String md5 = MD5Util.strToMd52(sign);
        if (StringUtils.isEmpty(md5)) {
            return null;
        }
        return md5.toLowerCase();
    }

    /**
     * 962	中信银行
     * 963	中国银行
     * 964	中国农业银行
     * 965	中国建设银行
     * 967	中国工商银行
     * 970	招商银行
     * 971	邮政储蓄
     *
     * @param traceId
     * @param bankName
     * @return
     */

    private String getBankType(String traceId, String bankName) {
        if (bankName.contains("中信银行")) {
            return "962";
        } else if (bankName.contains("中国银行")) {
            return "963";
        } else if (bankName.contains("农业银行")) {
            return "964";
        } else if (bankName.contains("建设银行")) {
            return "965";
        } else if (bankName.contains("工商银行")) {
            return "967";
        } else if (bankName.contains("招商银行")) {
            return "970";
        } else if (bankName.contains("邮政储蓄")) {
            return "971";
        } else if (bankName.contains("兴业银行")) {
            return "972";
        } else if (bankName.contains("浦发银行")||bankName.contains("浦东发展")) {
            return "977";
        } else if (bankName.contains("平安银行")) {
            return "978";
        } else if (bankName.contains("民生银行")) {
            return "980";
        } else if (bankName.contains("交通银行")) {
            return "981";
        } else if (bankName.contains("华夏银行")) {
            return "982";
        } else if (bankName.contains("广东发展银行")) {
            return "985";
        } else if (bankName.contains("光大银行")) {
            return "986";
        } else if (bankName.contains("支付宝")) {
            return "992";
        } else if (bankName.contains("财付通")) {
            return "993";
        } else {
            LogPortal.error("[{}]优卡代付银行不支持[{}]", traceId, bankName);
            return null;
        }
    }

    private String getOrderQuerySign(String orderno, String parter, String key) {
        String format = "orderid={0}&parter={1}{2}";
        String sign = MessageFormat.format(format, orderno, parter, key);
        String md5 = MD5Util.strToMd52(sign);
        if (StringUtils.isEmpty(md5)) {
            return null;
        }
        return md5.toLowerCase();
    }

    private  void orderCreateTest() {
        JSONObject inputParam = new JSONObject();
        inputParam.put("merchant_order_no","DF"+SnowFlakeUtils.getTraceId28());
        inputParam.put("amount","10");
        inputParam.put("account_name","孙余飞");
        inputParam.put("account_no","4392268386363833");
        inputParam.put("bank_name","招商银行");
        inputParam.put("bank_province","北京");
        inputParam.put("bank_city","北京");
        inputParam.put("bank_branch_bame","北京宣武门支行");
        inputParam.put("bank_branch_no","308100005125");
        inputParam.put("traceId",SnowFlakeUtils.getTraceId28());
        orderCreate(inputParam);
    }

    private  void orderQueryTest() {
        JSONObject inputParam = new JSONObject();
        inputParam.put("merchant_order_no","DF"+SnowFlakeUtils.getTraceId28());
        inputParam.put("traceId",SnowFlakeUtils.getTraceId28());
        orderQuery(inputParam);
    }

    public static void main(String[] args) {
//        YouKaPayHandler youKaPayHandler = new YouKaPayHandler();
//        youKaPayHandler.orderCreateTest();
//        youKaPayHandler.orderQueryTest();
    }


    public static BaseResData sendGet(String traceId,String methodDesc,String url,Map<String, String> paramMap){
        return sendGet(traceId,methodDesc,url,paramMap,0);
    }

    public static BaseResData sendGet(String traceId,String methodDesc,String url,Map<String, String> paramMap,int socketTimeoutSecond) {
        //声明返回结果
        String result = "";
        //开始请求API接口时间
        long startTime=System.currentTimeMillis();
        //请求API接口的响应时间
        long endTime= 0L;
        int responseCode=-1;
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = null;
        HttpEntity httpEntity = null;
        BaseResData baseResData = new BaseResData();
        try {
            // 设置链接超时等待时间
            if (socketTimeoutSecond ==0) { // 默认为2分钟
                socketTimeoutSecond = 120;
            }
            org.apache.http.client.config.RequestConfig requestConfig = org.apache.http.client.config.RequestConfig.custom().
                    setConnectTimeout(10 * 1000).
                    setConnectionRequestTimeout(10 * 1000).
                    setSocketTimeout(socketTimeoutSecond * 1000). //超时最大等待时间
                    build();
            // 创建连接
            if (url.startsWith("https")){
                httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setSSLSocketFactory(new SSLConnectionSocketFactory(getSslContext())).build();
            } else {
                httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
            }

            URIBuilder uriBuilder = new URIBuilder(url);
            if (paramMap != null && paramMap.size()>0){
                Iterator iterator = paramMap.entrySet().iterator();
                while(iterator.hasNext()){
                    Map.Entry<String,String> elem = (Map.Entry<String, String>) iterator.next();
                    uriBuilder.setParameter(elem.getKey(),elem.getValue());
                }
            }
            HttpGet httpGet = new HttpGet(uriBuilder.build());
            LogPortal.info("{} {}请求开始 URL:{} 请求参数:{}",traceId,methodDesc,url,paramMap);
            response = httpClient.execute(httpGet);
            responseCode = response.getStatusLine().getStatusCode();
            if (responseCode ==200){
                httpEntity = response.getEntity();
                if (httpEntity != null) {
                    Charset charset = Charset.forName("UTF-8");
                    result = EntityUtils.toString(httpEntity,charset);
                    baseResData.setData(result);
                }
                if (StringUtils.isEmpty(result)){
                    baseResData.setRespMsg("响应报文内容为空");
                } else {
                    baseResData.setSuccess(true);
                }
            } else {
                baseResData.setRespMsg("HttpStatus非200，当前是:"+responseCode);
            }
        } catch (ConnectTimeoutException e) {
            baseResData.setRespMsg(e.getClass().getName().concat(" 异常描述:".concat(e.getMessage())));
        } catch (SocketTimeoutException e) {
            baseResData.setProcessing(true);
            baseResData.setRespMsg(e.getClass().getName().concat(" 异常描述:".concat(e.getMessage())));
        }catch (SocketException e) {
            baseResData.setRespMsg(e.getClass().getName().concat(" 异常描述:".concat(e.getMessage())));
        } catch (Exception e) {
            baseResData.setRespMsg("发生"+e.getClass().getName()+"异常，错误码:"+traceId);
            LogPortal.error("{} {}http请求发生{}异常",e,traceId,methodDesc,e.getClass().getName());
        } finally {
            try {
                if (httpEntity != null){
                    EntityUtils.consume(httpEntity);
                }
            } catch (IOException e) {
                LogPortal.error("{} {}http请求释放资源异常",e,traceId,methodDesc);
            }
        }
        //请求接口的响应时间
        endTime=System.currentTimeMillis();
        LogPortal.info("{} {}耗时:{}ms httpStatus:{} 响应报文:{}",traceId,methodDesc,(endTime-startTime),responseCode,result);
        return baseResData;
    }

    private String encodeGb2312Str(String str){
        try {
            return URLEncoder.encode(str,"gb2312");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "";
    }

    private static SSLContext getSslContext() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, new TrustManager[]{new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
            }
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
            }
        }}, new SecureRandom());
        return sslContext;
    }

    private JSONObject strToJson(String result){
        JSONObject dataJson = new JSONObject();
        if (StringUtils.isNotEmpty(result) && result.contains("&")){
            String [] resultArry = result.split("&");
            for (String resultArryItem :resultArry){
                if (resultArryItem.indexOf("=")>0){
                    String [] resultArryItemArry = resultArryItem.split("=");
                    if (resultArryItemArry.length==2){
                        dataJson.put(resultArryItemArry[0],resultArryItemArry[1]);
                    } else {
                        dataJson.put(resultArryItemArry[0],"");
                    }
                }
            }
        }
        return dataJson;
    }

    private SubstitutePayConfigDTO getSubstitutePayConfigDTOTest(){
        SubstitutePayConfigDTO substitutePayConfigDTO = new SubstitutePayConfigDTO();
        WanXiangPayConfigParamVO wanXiangPayConfigParamVO2 = new WanXiangPayConfigParamVO();
        wanXiangPayConfigParamVO2.setWebsite("http://pay.7uka.com");
        wanXiangPayConfigParamVO2.setKey("7eaa05db106e45febe6518284357940d");
        wanXiangPayConfigParamVO2.setParter("1000");
        wanXiangPayConfigParamVO2.setNotifyurl("http://uatxy.xyouplay.com");
        substitutePayConfigDTO.setWanXiangPayConfigParamVO(wanXiangPayConfigParamVO2);
        return substitutePayConfigDTO;
    }
}
